iT邦幫忙

2023 iThome 鐵人賽

DAY 24
0
Software Development

開心撰寫 PHPUnit系列 第 24

Day 24. 判斷測試的種類 - 把測試移到合適的地方

  • 分享至 

  • xImage
  •  

在我們要完成 PttCrawler 這隻程式之前,我們再 review 一下 PttCrawler 的程式碼(這是上次隨意撰寫的程式碼,所以程式不一定能夠正常執行)

<?php
// src/PttCrawler.php

namespace Recca0120\Ithome30;

use Psr\Http\Client\ClientInterface;
use Recca0120\Ithome30\Crawlers\Home;
use Recca0120\Ithome30\Crawlers\Board;

class PttCrawler
{
    public function __construct(private ClientInterface $httpClient)
    {
    }

    public function all()
    {
        $crawler = new Home($this->httpClient);
        $boardCrawler = new Board($this->httpClient);

        $results = [];
        foreach ($crawler->all() as $board) {
            foreach ($boardCrawler->fetch($board) as $articles) {
                $results[] = $articles;
            }
        }

        return $results;
    }
}

這時會發現 PttCrawler 我們要測試的會是 HomeBoard 這兩隻 class 的一起產生出資料的情境,但我們目前寫好的 PttCrawlerTest 實際上是在測試 Home 這隻程式碼,所以 PttCrawlerTest 的測試內容是不符合情境的,經過這樣的分析,我們應該把 PttCrawlerTest 改為 HomeTest 才對,但需要重新再寫一次測試嗎?不用,我們只需 copy PttCrawlerTest 內容到 HomeTest 並修改 assertEquals 即可,所以我們會產出以下的程式碼

<?php

namespace Recca0120\Ithome30\Tests\Crawlers;

use Mockery;
use GuzzleHttp\Client;
use GuzzleHttp\Psr7\Request;
use PHPUnit\Framework\TestCase;
use Recca0120\Ithome30\Crawlers\Home;

class HomeTest extends TestCase
{

    public function test_fetch_board_page()
    {
        \VCR\VCR::turnOn();
        \VCR\VCR::insertCassette('ptt_home.yaml');

        /** @var Mockery\Mock|ClientInterface $httpClient */
        $httpClient = Mockery::spy(new Client());

        $crawler = new Home($httpClient);
        $records = $crawler->all();

        self::assertEquals([
            'title' => '[八卦] 亞運李智凱、許皓鋐奪金!',
            'url' => 'https://www.ptt.cc/bbs/Gossiping/index.html',
            'name' => 'Gossiping',
            'nuser' => '8803',
            'class' => '綜合',
        ], $records[0]);

        $httpClient->shouldHaveReceived('sendRequest')->once()->with(Mockery::on(function (Request $request) {
            return (((string)$request->getUri()) === 'https://www.ptt.cc/bbs/hotboards.html');
        }));

        \VCR\VCR::eject();
        \VCR\VCR::turnOff();
    }
}

這樣調整完後是不是發現 PttCrawlerTest 幾乎等於沒用處了?是的!因為 PttCrawler 的程式碼內容的主體是 Home, Board 兩個 class 的互動而不是抓取頁面的過程,所以產出 HomeTest 是保護抓取首頁的過程,而 PttCrawlerTest 我們要重新撰寫測試來讓我們只需專注在 Home 及 Board 的互動!


上一篇
Day 23. 使用 Generator 重構分頁 - 更快速得到回應
下一篇
Day 25. 兩個物件互動測試 - Mock
系列文
開心撰寫 PHPUnit30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言